#Copyright 2009-2010 by Ward, David J ( pymethius@ominian.net )
from logging import getLogger
log = getLogger(__name__)

import inspect
import types

from twisted.python import reflect

from webmud.lib import config

class RoutesFactory(object):
    def __init__(self, dbpool):
        log.debug("RoutesFactor Initialized")
        self.config = config.require("auth")
        self.routes = {}
        self.dbpool = dbpool
        self.buildBaseRoutes()
    
    def buildBaseRoutes(self):        
        d = self.dbpool.runQuery("SELECT * FROM routes ")
        d.addCallback(self._buildBaseRoutes)
        d.addErrback(self._failHorrible)
    
    def _buildBaseRoutes(self, result):
        for row in result:
            id, type, key, handler = row
            
            if not self.config.has_key(type,):
                self.config[type] = {}
            self.config[type][key] = handler
    
    def _failHorrible(self, *args):
        print "Failed building up routes! %s " % args        
    
    
    
    def userRoutes(self, userType):
        """
            Dedicated memoization function for getRoutes
        """
        if not self.routes.has_key(userType):
            self.routes[userType] = self._userRoutes(userType)
        
        return self.routes[userType].copy()

    def _userRoutes(self, userType):
        routes = self.config["default"].copy() 
        userRoutes = self.config.get( userType, {})
        
        for name, path in userRoutes.items():
            routes[name] = path
        
        return routes
    
    def build(self, userType):
        routes = self.userRoutes(userType)        
        log.debug("Returning for userType %s routes %s" %(userType, routes) )
        return RouteParser(routes)



class RouteParser(object):
    
    def __init__(self, routes):
        self.routes = routes
    
    def getHandlerMethod(self, rawMethod):
        """
            Input: str(rawMethod) in format "handler"|"handler.method"
            returns (str:handlerName, str:methodName,) 
        """
        handler = None
        method = "index"
        
        elements = rawMethod.split(".",1)
        if len(elements) == 1:
            handler = elements[0]
        elif len(elements) == 2:
            handler, method = elements
        else:
            raise ValueError("Input must be in the format [\"handler\"|\"handler.method\"]")
        
        return (handler, method,)
            
    def getInstance(self, handler, environ):
        """
            Allow exceptions to bubble up and out
        """
        try:
            trueHandler = self.routes[handler]
        except KeyError:
            log.exception("No handler for %s in %s" % (handler, self.routes,))
            raise
        
        if not isinstance( trueHandler, types.StringTypes):            
            if trueHandler.environ['user'] == environ['user']:
                return trueHandler(environ)
            else:
                raise Exception("PANIC - Security failure")    
        
        #There shall be an exception here if trueHandler != String        
        cls = reflect.namedClass(trueHandler)
                
                
        self.routes[handler] = cls(environ)
        
        return self.routes[handler]
        
    def isSafeCall(self, obj, method):
        return True #Hotwired for moment
        for cls in inspect.getmro(obj.__class__):
            if method in cls.__dict__: return True
            #Base is the LAST tier of classes before we get into object/platform support libraries
            if "Base" == cls.__name__: return False            
        return False
    
    def getAction(self, message, environ):
        handler, method = self.getHandlerMethod(message.method)
        if method[0] == "_":
            raise Exception("Unauthorized/invalid request to %s", method)
            
        obj = self.getInstance(handler, environ)
        
        if self.isSafeCall(obj, method):
            return getattr(obj, method)
        else:
            raise Exception("Unsafe call attempted at %s.%s" % ( obj, method, ))
        
    def __call__(self, message, environ):
        log.debug("Routing %s " % message.method )
        
        action = self.getAction(message, environ)
        
        log.debug("Handling %s:%s( %s ) w/%s" % (message.id, message.method, message.params,  action))
        
        if isinstance(message, types.StringTypes):
            return action(message.id, message.params)
            
        elif isinstance(message.params, types.ListType ):
            return action(message.id, *message.params )
            
        elif isinstance(message.params,  types.DictionaryType ):
            return action(message.id, **message.params)
            
        else:
            #no idea, let the action figure it out if it can
            return action(message.id, message.params)
        
        
    
    